"======================================================================
"
" confirm.vim -
"
" Created by skywind on 2021/12/11
" Last Modified: 2021/12/13 22:07
"
"======================================================================

" vim: set ts=4 sw=4 tw=78 noet :


"----------------------------------------------------------------------
" build buttons
"----------------------------------------------------------------------
function! s:button_prepare(choices)
    let choices = quickui#utils#text_list_normalize(a:choices)
    let items = []
    let index = 0
    let max_size = 4
    for choice in choices
        let item = quickui#utils#item_parse(choice)
        let item.index = index
        let items += [item]
        let width = item.text_width
        let max_size = (max_size < width)? width : max_size
        let index += 1
    endfor
    for item in items
        let width = item.text_width
        let pad1 = (max_size - width) / 2
        let pad2 = max_size - width - pad1
        " let pad1 += 1
        " let pad2 += 1
        let item.text = repeat(' ', pad1) . item.text . repeat(' ', pad2)
        if item.key_pos >= 0
            let item.key_pos += pad1
        endif
        let item.text_width = strwidth(item.text)
    endfor
    return items
endfunc


"----------------------------------------------------------------------
" synthesis button line
"----------------------------------------------------------------------
function! s:button_finalize(items, style)
    let items = a:items
    let final = ''
    let start = 0
    let index = len(a:items) - 1
    for item in a:items
        if 0
            let text = ' ' . item.text . ' '
        else
            let text = '<' . item.text . '>'
        endif
        let item.offset = -1
        let need = 0
        if 0
            let need = 1
            let text = '[' . text . ']'
        endif
        if item.key_pos >= 0
            let item.offset = start + 1 + item.key_pos + need
        endif
        let item.start = start
        let item.endup = start + item.text_width + 2 + need * 2
        let start += item.text_width + 2 + need * 2
        let final .= text
        if index > 0
            let final .= '  '
            let start += 2
        endif
        let index -= 1
    endfor
    return final
endfunc


"----------------------------------------------------------------------
" create highlight
"----------------------------------------------------------------------
function! s:hl_prepare(hwnd)
    let hwnd = a:hwnd
    let c1 = get(g:, 'quickui_button_color_on', 'QuickSel')
    let c2 = get(g:, 'quickui_button_color_off', 'QuickBG')
    let ck = get(g:, 'quickui_button_color_key', 'QuickKey')
    let hwnd.color_on = c1
    let hwnd.color_off = c2
    let hwnd.color_on2 = 'QuickButtonOn2'
    let hwnd.color_off2 = 'QuickButtonOff2'
    call quickui#highlight#clear('QuickBUttonOn2')
    call quickui#highlight#clear('QuickBUttonOff2')
    if 0
        call quickui#highlight#overlay('QuickButtonOn2', c1, ck)
        call quickui#highlight#overlay('QuickButtonOff2', c2, ck)
    else
        call quickui#highlight#make_underline('QuickButtonOn2', c1)
        call quickui#highlight#make_underline('QuickButtonOff2', c2)
    endif
endfunc


"----------------------------------------------------------------------
" calculate requirements
"----------------------------------------------------------------------
function! s:init(text, choices, index, title)
    let hwnd = {}
    let hwnd.text = quickui#utils#text_list_normalize(a:text)
    let hwnd.items = s:button_prepare(a:choices)
    let hwnd.final = s:button_finalize(hwnd.items, 0)
    let hwnd.index = a:index
    let button = ''
    let text_size = 40
    for text in hwnd.text
        let ts = strdisplaywidth(text)
        let text_size = (text_size < ts)? ts : text_size
    endfor
    let limit = &columns * 80 / 100
    let limit = get(g:, 'quickui_confirm_max_width', limit)
    let text_size = (text_size < limit)? text_size : limit
    let hwnd.btn_size = strdisplaywidth(hwnd.final)
    let hwnd.text_size = text_size
    let hwnd.w = (hwnd.btn_size > text_size)? hwnd.btn_size : text_size
    let hwnd.h = len(hwnd.text) + 3
    let hwnd.tw = hwnd.w + 4
    let hwnd.th = hwnd.h + 4
    let border = g:quickui#style#border
    let opts = {}
    let opts.w = hwnd.w
    let opts.h = hwnd.h
    let opts.border = get(g:, 'quickui_confirm_border', border)
    let opts.center = 1
    let opts.title = (a:title == '')? '' : (' ' . a:title . ' ')
    let opts.padding = [1, 1, 1, 1]
    let opts.button = 1
    let opts.wrap = 1
    let hwnd.opts = opts
    let content = deepcopy(hwnd.text)
    let content += [' ', ' ']
    let hwnd.padding = hwnd.w - hwnd.btn_size
    let content += [repeat(' ', hwnd.padding) . hwnd.final]
    let hwnd.content = content
    let hwnd.win = quickui#window#new()
    let hwnd.keymap = quickui#utils#keymap()
    let index = 1
    for item in hwnd.items
        if item.key_pos >= 0
            let ch = tolower(item.key_char)
            let hwnd.keymap[ch] = 'ACCEPT:' . index
        endif
        let index += 1
    endfor
    let hwnd.keymap['h'] = 'LEFT'
    let hwnd.keymap['l'] = 'RIGHT'
    call s:hl_prepare(hwnd)
    return hwnd
endfunc


"----------------------------------------------------------------------
"
"----------------------------------------------------------------------
function! s:draw_button(hwnd, index)
    let hwnd = a:hwnd
    let item = hwnd.items[a:index]
    let index = a:index
    let win = hwnd.win
    let top = hwnd.h - 1
    let off = hwnd.padding
    let x = item.start
    let e = item.endup
    if hwnd.index == index
        let c1 = hwnd.color_on
        let c2 = hwnd.color_on2
    " let c1 = 'QuickSel'
    else
        let c1 = hwnd.color_off
        let c2 = hwnd.color_off2
        " let c1 = 'QuickBG'
        " return
    endif
    if item.offset < 0
        call win.syntax_region(c1, off + x, top, off + e, top)
    else
        let u = item.offset + off
        call win.syntax_region(c1, off + x, top, u, top)
        call win.syntax_region(c2, u, top, u + 1, top)
        call win.syntax_region(c1, u + 1, top, off + e, top)
    endif
endfunc


"----------------------------------------------------------------------
" render
"----------------------------------------------------------------------
function! s:render(hwnd)
    let hwnd = a:hwnd
    let win = hwnd.win
    let off = hwnd.padding
    let top = hwnd.h - 1
    let index = 0
    call win.syntax_begin(1)
    for item in hwnd.items
        call s:draw_button(hwnd, index)
        let index += 1
    endfor
    " call win.syntax_region(ck, 12, 0, 13, 0)
    call win.syntax_end()
endfunc


"----------------------------------------------------------------------
" main entry
"----------------------------------------------------------------------
function! quickui#confirm#open(text, ...)
    let choices = (a:0 < 1)? " &OK " : (a:1)
    let index = (a:0 < 2)? 1 : (a:2)
    let title = (a:0 < 3)? 'Confirm' : (a:3)
    let choices = (choices == '')? " &OK " : choices
    let hwnd = s:init(a:text, choices, index - 1, title)
    let win = hwnd.win
    let accept = 0
    let size = len(hwnd.items)

    if size == 0
        return 0
    endif

    if has('nvim')
        let hwnd.opts.focusable = 1
    endif

    call win.open(hwnd.content, hwnd.opts)

    while 1
        call s:render(hwnd)
        redraw
        let ch = quickui#utils#getchar(1)
        if ch == "\<c-c>" || ch == "\<esc>"
            let accept = 0
            break
        elseif ch == "\<space>" || ch == "\<cr>"
            let accept = hwnd.index + 1
            break
        elseif win.quit != 0
            let accept = 0
            break
        elseif ch == "\<LeftMouse>"
            if has('nvim') == 0
                let pos = getmousepos()
                let x = pos.column - 1
                let y = pos.line - 1
            else
                let x = v:mouse_col - 1
                let y = v:mouse_lnum - 1
            endif
            if v:mouse_winid == win.winid
                if y == hwnd.h - 1 && x >= hwnd.padding
                    let u = x - hwnd.padding
                    for item in hwnd.items
                        if u >= item.start && u < item.endup
                            let accept = item.index + 1
                            break
                        endif
                    endfor
                    if accept > 0
                        break
                    endif
                endif
            elseif v:mouse_winid == win.info.border_winid
                if y == 0 && x == win.info.tw - 1
                    let accept = 0
                    break
                endif
            endif
        else
            let key = get(hwnd.keymap, ch, ch)
            if key == 'LEFT'
                let hwnd.index = (hwnd.index > 0)? (hwnd.index - 1) : 0
            elseif key == 'RIGHT'
                if hwnd.index < size - 1
                    let hwnd.index += 1
                endif
            elseif key == 'HOME' || key == 'UP' || key == 'PAGEUP'
                let hwnd.index = 0
            elseif key == 'END' || key == 'DOWN' || key == 'PAGEDOWN'
                let hwnd.index = size - 1
            elseif key =~ '^ACCEPT:'
                let key = strpart(key, 7)
                let index = str2nr(key)
                if index > 0 && index <= size
                    let accept = index
                    break
                endif
            endif
        endif
    endwhile

    if accept > 0 && win.quit == 0
        let hwnd.index = accept - 1
        call s:render(hwnd)
        redraw
        sleep 15m
    endif

    call win.close()

    return accept
endfunc



